﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Principal;
using System.Threading;
using NetFrameworkExtensions.Enterprise.Properties;

namespace NetFrameworkExtensions.Enterprise.Security
{
  [Serializable]
  public class IdentityBase<TIdentity> :
    IIdentity
    where TIdentity : IdentityBase<TIdentity>
  {
    public IdentityBase(string name, string authenticationType)
    {
      if (name == null)
        throw new ArgumentNullException("userName");
      if (authenticationType == null)
        throw new ArgumentNullException("authenticationType");

      Name = name;
      AuthenticationType = authenticationType;
    }

    public IdentityBase()
    {
      Name = String.Empty;
      AuthenticationType = "None";
    }


    public string Name { get; private set; }

    public string AuthenticationType { get; private set; }

    public bool IsAuthenticated { get { return Name.Equals(String.Empty); } }

    public sealed override bool Equals(object obj)
    {
      if (obj == null) return false;
      if (!IsAuthenticated)
      {
        var other = obj as IIdentity;
        if (other == null) return false;
        return !other.IsAuthenticated;
      }
      else
      {
        if (!typeof(TIdentity).IsAssignableFrom(obj.GetType()))
          return false;
        var other = (TIdentity)obj;
        if (!other.IsAuthenticated)
          return false;
        return EqualsOverride(other);
      }
    }

    protected virtual bool EqualsOverride(TIdentity other)
    {
      return AuthenticationType == other.AuthenticationType &&
             Name == other.Name;
    }

    public sealed override int GetHashCode()
    {
      if (!IsAuthenticated)
        return 524287;
      return GetHashCodeOverride();
    }

    protected virtual int GetHashCodeOverride()
    {
      unchecked
      {
        return Name.GetHashCode();
      }
    }

    public override string ToString()
    {
      if (!IsAuthenticated)
        return FormattedResources.UnauthenticatedUserToString;
      return ToStringOverride();
    }

    protected virtual string ToStringOverride()
    {
      return Name;
    }

    public static TIdentity Current
    {
      get
      {
        var principal = Thread.CurrentPrincipal;
        if (principal == null) return null;
        var identity = principal.Identity;
        return identity as TIdentity;
      }
    }

    public static bool CurrentIsAuthenticated
    {
      get
      {
        var identity = Current;
        return identity != null && identity.IsAuthenticated;
      }
    }
  }
}
